#include "StdAfx.h"
#include "dsegen.h"
#include "DsegenTypes.h"
#include "CalcDissimilarity.h"

namespace dhis
{

	CParameter::CParameter(void)
	{
		m_initThreshold = 20.0;
		m_startScale = 100.0;
		m_stopScale = 500.0;

		m_scaleFactor = 1.15;
		m_scalePrecision = 0;

		m_shapeWeight = 1.0;
		m_comptWeight = 0.5;

		m_customScale = false;

		m_dataDivideType = divide1024;

		m_spectralDC = sdcSpectralSDSBSMV;
		m_shapeDC = sdcShapeCompactness;
	}

	CParameter::CParameter(const CParameter& other)
	{
		m_initThreshold = other.m_initThreshold;
		m_startScale = other.m_startScale;
		m_stopScale = other.m_stopScale;

		m_shapeWeight = other.m_shapeWeight;
		m_comptWeight = other.m_comptWeight;

		m_scaleFactor = other.m_scaleFactor;
		m_customScale = other.m_customScale;
		m_scales = other.m_scales;
		m_scalePrecision = other.m_scalePrecision;

		m_dataDivideType = other.m_dataDivideType;

		m_spectralDC = other.m_spectralDC;
		m_shapeDC = other.m_shapeDC;
	}

	CParameter& CParameter::operator=(const CParameter& other)
	{
		if (this != &other)
		{
			m_initThreshold = other.m_initThreshold;
			m_startScale = other.m_startScale;
			m_stopScale = other.m_stopScale;

			m_shapeWeight = other.m_shapeWeight;
			m_comptWeight = other.m_comptWeight;

			m_scaleFactor = other.m_scaleFactor;
			m_customScale = other.m_customScale;
			m_scales = other.m_scales;
			m_scalePrecision = other.m_scalePrecision;

			m_dataDivideType = other.m_dataDivideType;

			m_spectralDC = other.m_spectralDC;
			m_shapeDC = other.m_shapeDC;
		}
		return *this;
	}

	CParameter::~CParameter(void)
	{

	}

	void CParameter::Normalize()
	{
		if (m_comptWeight > 0.9) { m_comptWeight = 0.9; }
		if (m_comptWeight < 0.1) { m_comptWeight = 0.1; }
		if (m_shapeWeight < 0.0) { m_shapeWeight = 0.0; }
		if (m_shapeWeight > 0.9) { m_shapeWeight = 0.9; }
		if (m_scaleFactor < 1.01) { m_scaleFactor = 1.01; }
		if (m_scalePrecision < 0) { m_scalePrecision = 0; }
		if (m_scalePrecision >= 4) { m_scalePrecision = 4; }
		if (sdcSpectralMin > m_spectralDC && sdcSpectralMax < m_spectralDC) { m_spectralDC = sdcSpectralSDSBSMV; }
		if (sdcShapeMin > m_shapeDC && sdcShapeMax < m_shapeDC) { m_shapeDC = sdcShapeCompactness; }
	}

	bool CParameter::ExportToXMLFile(const char* szFileName)
	{
		int rc;
		xmlTextWriterPtr writer;
		xmlChar *tmpXmlChar;
		std::stringstream ss;

		writer = xmlNewTextWriterFilename(szFileName, 0);
		if (writer == NULL) {
			printf("testXmlwriterFilename: Error creating the xml writer\n");
			return false;
		}

		rc = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
		assert(rc >= 0);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "Parameter");
		rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST "ImageSegment");
		rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0");
		assert(rc >= 0);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "DataDivideType");
		ss << m_dataDivideType;
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "InitThreshold");
		ss << m_initThreshold;
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "ShapeWeight");
		ss << m_shapeWeight;
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "ComptWeight");
		ss << m_comptWeight;
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "ScalePrecision");
		ss << m_scalePrecision;
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		std::string szBool("false");
		if (m_customScale) { szBool = "true"; }
		rc = xmlTextWriterStartElement(writer, BAD_CAST "CustomScale");
		rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST szBool.c_str());
		if (m_customScale) { ss << m_scales.size(); } else { ss << 0; }
		rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "count", BAD_CAST ss.str().c_str());
		ss.str("");

		if (m_customScale)
		{
			for (std::set<REAL>::iterator  itr = m_scales.begin(); itr != m_scales.end(); ++itr)
			{
				ss << *itr;
				rc = xmlTextWriterStartElement(writer, BAD_CAST "Scale");
				rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
				ss.str("");
				rc = xmlTextWriterEndElement(writer);
			}
			rc = xmlTextWriterEndElement(writer);
		} else {
			rc = xmlTextWriterEndElement(writer);

			rc = xmlTextWriterStartElement(writer, BAD_CAST "StartScale");
			ss << m_startScale;
			rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
			ss.str("");
			rc = xmlTextWriterEndElement(writer);

			rc = xmlTextWriterStartElement(writer, BAD_CAST "StopScale");
			ss << m_stopScale;
			rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
			ss.str("");
			rc = xmlTextWriterEndElement(writer);

			rc = xmlTextWriterStartElement(writer, BAD_CAST "ScaleFactor");
			ss << m_scaleFactor;
			rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
			ss.str("");
			rc = xmlTextWriterEndElement(writer);
		}
		
		rc = xmlTextWriterStartElement(writer, BAD_CAST "SpectralDissimilarityCriterion");
		ss << ((int)(m_spectralDC));
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterStartElement(writer, BAD_CAST "ShapeDissimilarityCriterion");
		ss << ((int)(m_shapeDC));
		rc = xmlTextWriterWriteString(writer, BAD_CAST ss.str().c_str());
		ss.str("");
		rc = xmlTextWriterEndElement(writer);

		rc = xmlTextWriterEndDocument(writer);
		assert(rc >= 0);

		xmlFreeTextWriter(writer);

		return true;
	}

	bool CParameter::ImportFromXMLFile(const char* szFileName)
	{
		xmlDocPtr doc = NULL;
		xmlNodePtr curNode = NULL;
		xmlChar* szKey;

		doc = xmlReadFile(szFileName,"UTF-8",XML_PARSE_RECOVER);
		if (NULL == doc)
		{
			printf("xmlReadFile: Error parse the xml file\n");
			return false;
		}

		curNode = xmlDocGetRootElement(doc);
		if (NULL == curNode)
		{
			fprintf(stderr,"empty document\n");
			xmlFreeDoc(doc);
			return false;
		}

		if (xmlStrcmp(curNode->name, BAD_CAST "Parameter"))
		{
			fprintf(stderr,"document of the wrong type, root node != Parameter");
			xmlFreeDoc(doc);
			return false;
		}

		if (!xmlHasProp(curNode,BAD_CAST"name"))
		{
			fprintf(stderr,"document of the wrong type, root node hasn't the name property");
			xmlFreeDoc(doc);
			return false;
		}

		szKey = xmlGetProp(curNode,BAD_CAST "name");
		if (xmlStrcmp(szKey, BAD_CAST "ImageSegment"))
		{
			fprintf(stderr,"document of the wrong type, root node's property is not ImageSegment");
			xmlFreeDoc(doc);
			return false;
		}
		xmlFree(szKey);

		xmlXPathContextPtr xpathCtx;
		xmlXPathObjectPtr result;
		xmlNodeSetPtr nodeSet;

		xmlChar* xpath;
		xmlChar *szValue;

		xpathCtx = xmlXPathNewContext(doc);

		xpath = BAD_CAST ("/Parameter/DataDivideType");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		xmlXPathFreeObject(result);
		m_dataDivideType = atoi((char *)szValue);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/InitThreshold");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		xmlXPathFreeObject(result);
		m_initThreshold = atof((char *)szValue);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/ShapeWeight");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		xmlXPathFreeObject(result);
		m_shapeWeight = atof((char *)szValue);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/ComptWeight");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		xmlXPathFreeObject(result);
		m_comptWeight = atof((char *)szValue);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/ScalePrecision");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		xmlXPathFreeObject(result);
		m_scalePrecision = atof((char *)szValue);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/CustomScale");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlGetProp(curNode,(const xmlChar *)"value");
		m_customScale = false;
		if (xmlStrcmp(szValue, BAD_CAST "false")) {
			m_customScale = true;
		}

		szValue = xmlGetProp(curNode,(const xmlChar *)"count");
		int count = atoi((char *)szValue);
		xmlXPathFreeObject(result);
		xmlFree(szValue);

		m_scales.clear();
		if (m_customScale)
		{
			xpath = BAD_CAST ("/Parameter/CustomScale/Scale");
			result = xmlXPathEvalExpression(xpath, xpathCtx);
			nodeSet = result->nodesetval;
			assert(nodeSet->nodeNr == count);
			for (int i=0; i < nodeSet->nodeNr; i++) {
				curNode = nodeSet->nodeTab[i];
				szValue = xmlNodeGetContent(curNode);
				m_scales.insert(atof((char *)szValue));
				xmlFree(szValue);
			}
			xmlXPathFreeObject(result);
		} else {
			xpath = BAD_CAST ("/Parameter/StartScale");
			result = xmlXPathEvalExpression(xpath, xpathCtx);
			nodeSet = result->nodesetval;
			curNode = nodeSet->nodeTab[0];
			szValue = xmlNodeGetContent(curNode);
			xmlXPathFreeObject(result);
			m_startScale = atof((char *)szValue);
			xmlFree(szValue);

			xpath = BAD_CAST ("/Parameter/StopScale");
			result = xmlXPathEvalExpression(xpath, xpathCtx);
			nodeSet = result->nodesetval;
			curNode = nodeSet->nodeTab[0];
			szValue = xmlNodeGetContent(curNode);
			xmlXPathFreeObject(result);
			m_stopScale = atof((char *)szValue);
			xmlFree(szValue);

			xpath = BAD_CAST ("/Parameter/ScaleFactor");
			result = xmlXPathEvalExpression(xpath, xpathCtx);
			nodeSet = result->nodesetval;
			curNode = nodeSet->nodeTab[0];
			szValue = xmlNodeGetContent(curNode);
			xmlXPathFreeObject(result);
			m_scaleFactor = atof((char *)szValue);
			xmlFree(szValue);
		}

		xpath = BAD_CAST ("/Parameter/SpectralDissimilarityCriterion");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		m_spectralDC = (eSpectralDissimilarityCriterion)(atoi((char *)szValue));
		xmlXPathFreeObject(result);
		xmlFree(szValue);

		xpath = BAD_CAST ("/Parameter/ShapeDissimilarityCriterion");
		result = xmlXPathEvalExpression(xpath, xpathCtx);
		nodeSet = result->nodesetval;
		curNode = nodeSet->nodeTab[0];
		szValue = xmlNodeGetContent(curNode);
		m_shapeDC = (eShapeDissimilarityCriterion)(atoi((char *)szValue));
		xmlXPathFreeObject(result);
		xmlFree(szValue);

		xmlXPathFreeContext(xpathCtx);

		xmlFreeDoc(doc);
		return true;
	}
}
